using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web.Hosting;
using System.Web.Script.Serialization;
using ScriptBehind.Compression;
using ScriptBehind.Core;
using ScriptBehind.Core.Interfaces;
using ScriptBehind.Extensions;

namespace ScriptBehind.Scripts
{
    [Serializable]
    internal class ScriptTransport
    {
        public string OrignalPath { get; set; }
        public string CompressionType { get; set; }
        public CompressionLevel CompressLevel { get; set; }
    }

    public sealed class LocalFileScript : ScriptBase
    {
        readonly string _fullPath;

        LocalFileScript(string scriptPath, InjectPosition injectPosition, ICompressionStrategy compression) 
        {
            OriginalPath = CleanPath(scriptPath);
            InjectPosition = injectPosition;
            FileName = Path.GetFileName(scriptPath);
            Compression = compression;
            _fullPath = HostingEnvironment.MapPath(OriginalPath);
        }

        internal LocalFileScript(ScriptTransport scriptTransport)
        {
            OriginalPath = CleanPath(scriptTransport.OrignalPath);
            InjectPosition = Core.InjectPosition.Default;
            FileName = Path.GetFileName(OriginalPath);
            Compression = CompressorFactory.Get(Type.GetType(scriptTransport.CompressionType), scriptTransport.CompressLevel);
            _fullPath = HostingEnvironment.MapPath(OriginalPath);
        }

        public string OriginalPath { get; set; }
        public string Content { get; set; }

        public string FullPath
        {
            get { return _fullPath; }
        }

        public override void TryConstruct(string from)
        {
            if (!Regex.IsMatch(from, @"[\\\/^\s]", RegexOptions.Singleline))
                FromPath(from);

        }

        public override IInjectionFormatter Formatter
        {
            get { return new LocalFileFormatter(); }
        }

        public static LocalFileScript FromPath(string path)
        {
            return FromPath(path, Core.InjectPosition.Default);
        }

        public static LocalFileScript FromPath(string path, InjectPosition injectPosition)
        {
            return FromPath(path, injectPosition, ScriptBehindCore.DefaultCompression);
        }

        public static LocalFileScript FromPath(string path, InjectPosition injectPosition, ICompressionStrategy compression)
        {
            return new LocalFileScript(path, injectPosition, compression);
        }

        public static LocalFileScript FromPath(string path, ICompressionStrategy compression)
        {
            return new LocalFileScript(path, Core.InjectPosition.Default, compression);
        }

        static string CleanPath(string path)
        {
            return Regex.Replace(path, @"[\/\\~]", "/");
        }

        internal string ToSerialized()
        {
            var ts = new ScriptTransport() { OrignalPath = OriginalPath, CompressionType = Compression.GetType().AssemblyQualifiedName, CompressLevel = Compression.CompressionLevel };
            var jss = new JavaScriptSerializer();
            return jss.Serialize(ts);
        }

    }

    public class LocalFileFormatter : InjectionFormatter
    {
        public LocalFileFormatter()
            : base("<script type='text/javascript' src='{0}'></script>")
        {
        }

        public override string Format(IScript script, bool seperate)
        {
            var typedScript = script as LocalFileScript;

            if (typedScript == null)
                return null;

            return seperate
                       ? InjectionFormatString.FormatWith(typedScript.ToEncodedUrl(ScriptBehindCore.HANDLER_URL_SEGMENT))
                       : typedScript.ToEncodedUrl("{0}");
        }

        public override string Format(IEnumerable<IScript> scripts, bool seperate)
        {
            if (scripts != null)
            {
                var result = ScriptBehindCore.HANDLER_URL_SEGMENT.FormatWith(scripts.Select(x => Format(x, false)).Join("-"));
                return seperate ? InjectionFormatString.FormatWith(result) : result;
            }

            return null;
        }
    }
}